package client;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;

import server.RightsHandler;

/**
 * Transceiver receives data from a stream and stores it in files. I can also
 * transmit data from a file through a stream.
 * 
 * @author Victor
 */
public abstract class Transceiver {
	private String documentRoot;
	public static final String END_OF_FILE = "END_OF_FILE";
	public static final String BEGINNING_OF_FILE = "BEGINNING_OF_FILE";
	public static final String JOURNAL_FILE_EXTENSION = ".journal";

	/**
	 * 
	 * @param documentRoot
	 *            is the path to where files will be received and sent from
	 */
	public Transceiver(String documentRoot) {
		this.documentRoot = documentRoot;
	}

	/**
	 * Returns an array of bytes containing the bytes for the file represented
	 * by the argument <b>path</b>.
	 * 
	 * @param path
	 *            is the path of the file relative to the <b>documentRoot</b>.
	 * @return the bytes for the file
	 * @exception FileNotFoundException
	 *                if the file corresponding to <b>path</b> could not be
	 *                loaded.
	 */
	protected byte[] getBytes(String path) throws IOException {
		System.out.println(path);
		File fileToRead = new File(path);
		int length = (int) (fileToRead.length());
		if (length == 0) {
			throw new IOException("File length is zero: " + path);
		} else {
			DataInputStream fileData = new DataInputStream(new FileInputStream(
					fileToRead));
			
			byte[] bytecodes = new byte[length];
			fileData.readFully(bytecodes);
			fileData.close();
			
			return bytecodes;
		}
	}

	/**
	 * Sends a file through a specified stream. When <b>BEGINNING_OF_FILE</b> is
	 * written to the output stream it means that the following data will
	 * contain the file, <b>END_OF_FILE</b> is sent when the file transfer is
	 * completed.
	 * 
	 * @param out
	 *            is the text-output stream where to send the file
	 * @param rawOut
	 *            is the raw byte output stream where to send the file
	 * @param path
	 *            is the path of the file relative to the <b>documentRoot</b>.
	 * @throws IOException
	 *             if unable to write to the output streams
	 */
	protected void sendFromFile(PrintWriter out, OutputStream rawOut,
			String file) throws IOException {
		String path = documentRoot + File.separator + file;
		
		byte[] bytecodes = getBytes(path);
		try {
			System.out.println("sending file " + file);

			out.print("receiving file " + file + "\r\n");
			out.println(BEGINNING_OF_FILE);
			out.flush();
			rawOut.write(bytecodes);
			rawOut.flush();
			out.println(END_OF_FILE);
			out.println("file received");
			out.flush();
		} catch (IOException ie) {
			return;
		}
	}

	/**
	 * Receives a file from the text-input stream <b>in</b> and writes it to a
	 * file.
	 * 
	 * @param in
	 *            is the text-input stream where to receive the file
	 * @param path
	 *            is the path of the file relative to the <b>documentRoot</b>.
	 */
	protected void writeToFile(BufferedReader in, String path) {
		try {
			String inputLine = in.readLine();
			BufferedWriter fileOut = new BufferedWriter(new FileWriter(
					documentRoot + File.separator + path));
			
			while (inputLine != null && !inputLine.contains(END_OF_FILE)) {
				fileOut.write(inputLine + "\r\n");
				inputLine = in.readLine();
			}
			if(!inputLine.equals(END_OF_FILE)) {
				fileOut.write(inputLine.substring(0, inputLine.indexOf(END_OF_FILE)) + "\r\n");
			}
			fileOut.close();
		} catch (Exception e) {
			System.err.println("Error writing to file: " + e.getMessage());
		}
	}
}
